//  IDVI 1.0 source copyright 1996 Garth A. Dickie
//
//  This source is free for non-commercial use.  No warranty, etc.
//  Please acknowledge reuse by including the line:
//
//  "Based in part on IDVI 1.0 source copyright 1996 Garth A. Dickie"
//
//  in your documentation and source code.  For commercial use or
//  distribution, please contact the author.  Please also send
//  questions, comments, bug reports, or fixes.
//
//  Best Regards,
//  Garth A. Dickie
//  dickie@elastic.avid.com

package ibook.v10.html;

import java.io.InputStream;
import java.io.IOException;
import java.io.EOFException;

public class HTMLScanner {
    //  The client looks at the character and specialCharacter fields to
    //  determine the next character.  The specialCharacter flag is true
    //  if the character appeared in the input as a '<', '>', or '"'.
    //  The sequences &lt; &gt; &quot; and &amp; are converted to the
    //  characters <>"&, respectively, with the specialCharacter flag set
    //  to false.

    public char     character;
    public boolean  specialCharacter;
    
    private InputStream stream;
    private StringBuffer specialBuffer = new StringBuffer( );

    public HTMLScanner( InputStream stream )
            throws HTMLFormatException, IOException {

        this.stream = stream;
        advance( );
    }

    //  advance( ) handles the work of checking for special characters.
    //  For this quick implementation with just the four &...; sequences,
    //  we just use string compare.  If we don't recognize a sequence,
    //  then it is presented as individual characters.

    public void advance( )
            throws HTMLFormatException, IOException {

        character = read( );
        specialCharacter = character == '<' || character == '>' || character == '"';

        if( character == '&' ) {
            specialBuffer.setLength( 0 );

            char next = read( );
            while( ! ( next == ';' || Character.isSpace( next ))) {
                specialBuffer.append( next );
                next = read( );
            }

            if( next != ';' )
                unread( next );
            
            String specialString = specialBuffer.toString( );

            if( "lt".equals( specialString ))
                character = '<';
            else if( "gt".equals( specialString ))
                character = '>';
            else if( "quot".equals( specialString ))
                character = '"';
            else if( "amp".equals( specialString ))
                character = '&';
            else {
                if( next == ';' ) unread( next );
                unread( specialString );
            }
        }
    }

    private StringBuffer pushbackBuffer = new StringBuffer( );

    private char read( )
            throws IOException, HTMLFormatException {

        char result;

        int pushbackLength = pushbackBuffer.length( );
        if( pushbackLength != 0 ) {
            result = pushbackBuffer.charAt( pushbackLength - 1 );
            pushbackBuffer.setLength( pushbackLength - 1 );
        } else {
            int next = stream.read( );
            if( next == -1 ) throw new HTMLFormatException( "Runaway HTML" );
            
            result = ( char ) next;
        }
            
        return result;
    }

    private void unread( char pushback ) {
        pushbackBuffer.append( pushback );
    }

    private void unread( String pushback ) {
        for( int i = pushback.length( ) - 1; i >= 0; -- i )
            unread( pushback.charAt( i ));
    }
}
